﻿#include "operatewindow.h"
#include <QDebug>
#include <QProcess>
#include "sys_h/SYS_VER.h"
#include "qstring_ex/qstringex.h"
#ifdef CUR_RUN_SYS_LINUX_QT
#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/XTest.h>
#define MAX_PROPERTY_VALUE_LEN 4096

#define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
#define _NET_WM_STATE_ADD           1    /* add/set property */
#define _NET_WM_STATE_TOGGLE        2    /* toggle property  */
#endif
#ifdef CUR_RUN_SYS_WINDOWS_VS2008
#include "windows.h"
#include "tlhelp32.h"
#include <stdio.h>
#include <tchar.h>
#include <shlobj.h> 
#endif
#ifdef CUR_RUN_SYS_LINUX_QT
    int EnumerateWindows (Display *display, Window rootWindow, int pid, int showErrors, int showStatus);
    int client_msg(Display* disp,Window win,char *msg,
            unsigned long data0, unsigned long data1,
            unsigned long data2, unsigned long data3,
            unsigned long data4);
    int showClientWindow(Display *disp, Window win,unsigned long action,_Xconst char* prop);
    int activateClientWindow(Display *disp, Window win);
#endif
OperateWindow::OperateWindow()
{
}
#ifdef CUR_RUN_SYS_WINDOWS_VS2008
typedef struct tWNDINFO
{
	DWORD dwProcessId;
	QList<HWND>	listhWnd;
}WinID;
BOOL CALLBACK myEnumProc(HWND hwnd,LPARAM lparam)
{
        DWORD dwProcessId=0;
		::GetWindowThreadProcessId(hwnd,&dwProcessId); //返回创建这个窗口的线程的id号
        WinID* pInfo = (WinID*)lparam;

        if (dwProcessId == pInfo->dwProcessId)
        {
			pInfo->listhWnd.append(hwnd);
        }
        return TRUE;
}
char* UnicodeToAnsi( const wchar_t* szStr )	//类型转换wchar_t* to char*
{
        int nLen = WideCharToMultiByte( CP_ACP, 0, szStr, -1, NULL, 0, NULL, NULL);
        if (nLen == 0)
        {
                return NULL;
        }
        char* pResult = new char[nLen];
        WideCharToMultiByte( CP_ACP, 0, szStr, -1, pResult, nLen, NULL, NULL);
        return pResult;
}
#endif

int OperateWindow::FindProcessIdByName(char* in_processName)
{
#ifdef CUR_RUN_SYS_WINDOWS_VS2008
        if (!in_processName)
        {
                return 0;
        }
        char str_processName[1024];
        memset(str_processName,0x0,sizeof(str_processName));
        sprintf(str_processName,"%s.exe",in_processName);
        PROCESSENTRY32 processInfo;
        processInfo.dwSize = sizeof(processInfo);

        HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);   //创建进程快照，参数：在快照中包含系统中所有的进程，快照当前进程
        if (processesSnapshot == INVALID_HANDLE_VALUE)	//调用失败返回INVALID_HANDLE_VALUE
        {
                return 0;
        }

        //Process First in snapshot and traverse the list.
        Process32First(processesSnapshot, &processInfo);
        //////////////////////////////////////////////////////////////////////////
        char* pResult=UnicodeToAnsi(processInfo.szExeFile);
        //////////////////////////////////////////////////////////////////////////
//      int ret=strcmp(str_processName,pResult);
		int ret=stricmp(str_processName,pResult);
        if (pResult)
        {
                delete pResult;
        }
        pResult=NULL;
        if (ret==0)
        {
                //Process exists.
                CloseHandle(processesSnapshot);
                return processInfo.th32ProcessID;
        }

        while ( Process32Next(processesSnapshot, &processInfo) )
        {
                pResult=UnicodeToAnsi(processInfo.szExeFile);
//              ret=strcmp(str_processName,pResult);
				ret=stricmp(str_processName,pResult);
                if (pResult)
                {
                        delete pResult;
                }
                pResult=NULL;
                if (ret==0)
                {
                        CloseHandle(processesSnapshot);
                        return processInfo.th32ProcessID;
                }
        }
        CloseHandle(processesSnapshot);
        return 0;
#endif
#ifdef CUR_RUN_SYS_LINUX_QT
        QProcess* proc=new QProcess();
        QString cmdStr=QString("pidof -s %1").arg(in_processName);
        proc->start(cmdStr);
        proc->waitForFinished();
        QString outputStr=QStringEx::fromLocal8Bit(proc->readAllStandardOutput());
        outputStr=outputStr.trimmed();
        if (proc)
        {
                delete proc;
        }
        proc=NULL;

        if (outputStr.isEmpty())
        {
                cmdStr.clear();
                outputStr.clear();
                return 0;
        }else
        {
                int pid=outputStr.toInt();
                cmdStr.clear();
                outputStr.clear();
                return pid;
        }
#endif
}
#ifdef CUR_RUN_SYS_LINUX_QT
int EnumerateWindows (Display *display, Window rootWindow, int pid,int showErrors, int showStatus)
{
   static int level = 0;
   Window parent;
   Window *children;
   Window *child;
   unsigned int noOfChildren;
   int status;
   int i;

   XTextProperty wmName;
   char **list;

   status = XGetWMName (display, rootWindow, &wmName);
   if ((status) && (wmName.value) && (wmName.nitems))
   {
      status = XmbTextPropertyToTextList (display, &wmName, &list, &i);
      if ((status >= Success) && (i) && (*list))
      {
  //          qDebug()<<"==================================================================";
            QString str=QStringEx::fromLocal8Bit((char*) strdup (*list));
 //           qDebug()<<"INFO - Found window with name: "<<str;

            Atom xa_prop_name;
            Atom xa_ret_type;
            int ret_format;
            unsigned long ret_nitems;
            unsigned long ret_bytes_after;
            unsigned char *ret_prop;
            int id;
            xa_prop_name = XInternAtom(display, "_NET_WM_PID", False);
 //           qDebug()<<"----------------------------------------------------"<<XGetAtomName(display,xa_prop_name);
            if (XGetWindowProperty(display, rootWindow, xa_prop_name, 0,
                                    MAX_PROPERTY_VALUE_LEN / 4,
                                    False, XA_CARDINAL, &xa_ret_type,
                                    &ret_format, &ret_nitems, &ret_bytes_after,
                                    &ret_prop) != Success)
            {
                 qDebug()<<"error";
            }
        else
        {
            if(ret_prop)
            {
                 memcpy(&id, ret_prop, 4);
//                 printf("window pid: %d\n", id);
//                 qDebug()<<"id: "<<id;
                 if(id==pid)
                 {
//                    XUnmapWindow(display,rootWindow);
//                    XMapWindow(display,rootWindow);
//                    XRaiseWindow(display,rootWindow);
//                    XFlush(display);
                     activateClientWindow(display,rootWindow);
                    return 1;
                 }
             }
        }
      }
   }

//   GetWindowProperties (display, rootWindow);

   level++;

   status = XQueryTree (display, rootWindow, &rootWindow, &parent, &children, &noOfChildren);

   if (status == 0)
   {
      if (showErrors)
         qDebug()<<"ERROR - Could not query the window tree. Aborting.\r\n";
      return 0;
   }

   if (noOfChildren == 0)
   {
      if (showErrors)
         qDebug()<<"ERROR - No children found. Aborting.\r\n";
      return 0;
   }
   else
   {
      if (showStatus)
         qDebug()<<"STATUS - %i number of child windows found.\r\n", noOfChildren;
   }

   for (i=0; i < noOfChildren; i++)
   {
      if(EnumerateWindows (display, children[i], pid,showErrors, showStatus))
      {
          return 1;
      }
   }

   XFree ((char*) children);
   return 0;
}

int client_msg(Display* disp,Window win,char *msg,unsigned long data0, unsigned long data1,
        unsigned long data2, unsigned long data3,
        unsigned long data4)
{
    XEvent event;
    long mask = SubstructureRedirectMask | SubstructureNotifyMask;

    event.xclient.type = ClientMessage;
    event.xclient.serial = 0;
    event.xclient.send_event = True;
    event.xclient.message_type = XInternAtom(disp, msg, False);
    event.xclient.window = win;
    event.xclient.format = 32;
    event.xclient.data.l[0] = data0;
    event.xclient.data.l[1] = data1;
    event.xclient.data.l[2] = data2;
    event.xclient.data.l[3] = data3;
    event.xclient.data.l[4] = data4;

    if (XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) {
        return EXIT_SUCCESS;
    }
    else {
        return EXIT_FAILURE;
    }
}

/*
  _NET_WM_STATE_SKIP_TASKBAR,不在任务栏中显示
  _NET_WM_STATE_FULLSCREEN,全屏
  _NET_WM_STATE_SKIP_PAGER
  _NET_WM_STATE_HIDDEN,隐藏
  _NET_WM_STATE_ABOVE,窗口置于最上层
  _NET_WM_STATE_BELOW,窗口置于最下层
*/
int showClientWindow(Display *disp, Window win,unsigned long action,_Xconst char* prop)
{
    Atom atom_prop1 = XInternAtom(disp,prop,False);
    return client_msg(disp,win,"_NET_WM_STATE",action,atom_prop1,0,0,0);
}
int activateClientWindow(Display *disp, Window win)
{
    client_msg(disp, win, "_NET_ACTIVE_WINDOW",0, 0, 0, 0, 0);
    XMapRaised(disp, win);
}

#endif

int OperateWindow::ShowDisktop()
{
#ifdef CUR_RUN_SYS_WINDOWS_VS2008
        CoInitialize(0);
        IShellDispatch4 * pdisp = NULL;
        CoCreateInstance(CLSID_Shell, NULL, CLSCTX_ALL, __uuidof(IShellDispatch4), (void **)&pdisp);
        pdisp->ToggleDesktop();  //  切换桌面的
        pdisp->Release();
        CoUninitialize();

		//ADD 20120304
		keybd_event(VK_LWIN, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
		keybd_event('D', 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
		keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
		keybd_event('D', 0, KEYEVENTF_KEYUP, 0);
		return 1;
#endif
#ifdef CUR_RUN_SYS_LINUX_QT
    unsigned long state=1; //1:on,0:off
    Display *display=XOpenDisplay (NULL);
    int ret=client_msg(display, DefaultRootWindow(display), "_NET_SHOWING_DESKTOP",
        state, 0, 0, 0, 0);
    XCloseDisplay(display);
    return ret;
#endif
}
void OperateWindow::ShowWindowByPID(int pid)
{
#ifdef CUR_RUN_SYS_WINDOWS_VS2008
	WinID wi;
	wi.dwProcessId = pid;
	EnumWindows(myEnumProc,(LPARAM)&wi);
	WINDOWINFO pwi;
        for( int i=0;i<wi.listhWnd.count();i++ )
	{
		HWND hWnd=wi.listhWnd.at(i);
		if( ::GetParent( hWnd )) 
		{
			continue ;
		}
		if( ! IsWindowVisible( hWnd ) ) 
		{
//			::ShowWindow(hWnd, SW_SHOW);
			continue ;
		}
		if( IsIconic( hWnd ) ) 
		{
//			::ShowWindow(hWnd, SW_SHOW);
			::ShowWindow(hWnd, SW_RESTORE);
		}
		::SetForegroundWindow( hWnd );
		::SetActiveWindow( hWnd );
		::SetFocus(hWnd);
	}
#endif
#ifdef CUR_RUN_SYS_LINUX_QT
	Display *display;
        int screen;
	display = XOpenDisplay (NULL);
        screen = DefaultScreen (display);
	Window rootWindow;
	rootWindow = RootWindow (display, screen);
	EnumerateWindows (display, rootWindow, pid, 0, 0);
	XCloseDisplay (display);
#endif
}

void OperateWindow::showAndActiveWindow(WId wid)
{
#if defined(Q_WS_WIN)
        if( ! IsWindowVisible(wid))
        {
			::ShowWindow(wid, SW_SHOW);
        }
        if( IsIconic(wid))
        {
			::ShowWindow(wid,SW_RESTORE);
        }
        ::SetForegroundWindow(wid);
        ::SetActiveWindow(wid);
#endif
#if defined(Q_WS_X11)
        Display *display=XOpenDisplay (NULL);
        showClientWindow(display,wid,_NET_WM_STATE_REMOVE,"_NET_WM_STATE_SKIP_TASKBAR");
        activateClientWindow(display,wid);
        XCloseDisplay (display);
#endif
}


QList<unsigned long> OperateWindow::FindAllPidsByName(char* in_processName)
{
	QList<unsigned long> list_pids;
#ifdef CUR_RUN_SYS_WINDOWS_VS2008
	if (!in_processName)
	{
		return list_pids;
	}
	char str_processName[1024];
	memset(str_processName,0x0,sizeof(str_processName));
	sprintf(str_processName,"%s.exe",in_processName);
	PROCESSENTRY32 processInfo;
	processInfo.dwSize = sizeof(processInfo);

	HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);   //创建进程快照，参数：在快照中包含系统中所有的进程，快照当前进程
	if (processesSnapshot == INVALID_HANDLE_VALUE)	//调用失败返回INVALID_HANDLE_VALUE
	{
		return list_pids;
	}

	//Process First in snapshot and traverse the list.
	Process32First(processesSnapshot, &processInfo);
	//////////////////////////////////////////////////////////////////////////
	char* pResult=UnicodeToAnsi(processInfo.szExeFile);
	//////////////////////////////////////////////////////////////////////////
	//      int ret=strcmp(str_processName,pResult);
	int ret=stricmp(str_processName,pResult);
	if (pResult)
	{
		delete pResult;
	}
	pResult=NULL;
	if (ret==0)
	{
		//Process exists.
		//CloseHandle(processesSnapshot);
		//return processInfo.th32ProcessID;
		list_pids.append(processInfo.th32ProcessID);
	}

	while ( Process32Next(processesSnapshot, &processInfo) )
	{
		pResult=UnicodeToAnsi(processInfo.szExeFile);
		//              ret=strcmp(str_processName,pResult);
		ret=stricmp(str_processName,pResult);
		if (pResult)
		{
			delete pResult;
		}
		pResult=NULL;
		if (ret==0)
		{
			//CloseHandle(processesSnapshot);
			//return processInfo.th32ProcessID;
			list_pids.append(processInfo.th32ProcessID);
		}
	}
	CloseHandle(processesSnapshot);
	return list_pids;
#endif
#ifdef CUR_RUN_SYS_LINUX_QT
	QProcess* proc=new QProcess();
	QString cmdStr=QString("pidof %1").arg(in_processName);
	proc->start(cmdStr);
	proc->waitForFinished();
	QString outputStr=QStringEx::fromLocal8Bit(proc->readAllStandardOutput());
	outputStr=outputStr.trimmed();
	if (proc)
	{
		delete proc;
	}
	proc=NULL;

	QStringList strlist=outputStr.split(" ");
	for(int i=0;i<strlist.count();i++)
	{
		QString strtemp=strlist.at(i);
		unsigned long pid=strtemp.trimmed().toULong();
		if(pid>0)
		{
			list_pids.append(pid);
		}
	}
	return list_pids;
#endif
}

void OperateWindow::ShowOtherSameWindows(unsigned long pid,char* processName)
{
	if (processName==NULL)
	{
		return ;
	}

	QList<unsigned long> list_pids=FindAllPidsByName(processName);
	list_pids.removeAll(pid);
	for (int i=0;i<list_pids.count();i++)
	{
		int pid_old=list_pids.at(i);
		OperateWindow::ShowWindowByPID(pid_old);
	}
}
